#include "stdafx.h"
#include "YUdpSession.h"
#include "YEndPoint.h"
#include <YSimpleSystem/IProactor.h>

namespace ysimple_network
{
	YUdpSession::YUdpSession(ysimple_system::IProactor& proactor, SOCKET socket, bool reusedSocket, RELEASE_UDP_SESSION_FUNCTOR releaseFunctor)
		: m_reused(reusedSocket)
		, m_proactor(proactor)
		, m_socket(socket)
		, m_releaseFunctor(releaseFunctor)
		, m_refCount(0)
		, m_disconnected(false)
	{
	}


	YUdpSession::~YUdpSession(void)
	{
	}

	void YUdpSession::release()
	{
		if (--m_refCount == 0)
		{
			m_releaseFunctor(this);
			delete this;
		}
	}


	void YUdpSession::addRef()
	{
		++m_refCount;
	}


	bool YUdpSession::init()
	{
		return true;
	}

	bool YUdpSession::bind( const YEndPoint& endPoint )
	{
		if(::bind(m_socket, (SOCKADDR*)&endPoint.getAddressInfo(), endPoint.getAddressInfoSize()) == SOCKET_ERROR)
		{
			return false;
		}

		if (false == getProactor().associate((HANDLE)getSocket(), this))
		{
			return false;
		}

		return true;
	}

	SOCKET YUdpSession::getSocket() const 
	{
		return m_socket;
	}

	bool YUdpSession::sendto( const YEndPoint& toEndPoint, PACKET_SPTR packet, ISendToCallback& callback )
	{
		if (packet->written() == 0)	return false;

		DWORD dwFlags = 0;
		DWORD dwBytes = 0;
		
		YProactorTokenOnSendTo* pSendToToken = new YProactorTokenOnSendTo;
		pSendToToken->beginInit(packet, callback, *this, toEndPoint);
		int nBytesRecv = WSASendTo(m_socket
			, pSendToToken->getWSABuf()
			, pSendToToken->getWSABufCount()
			, &dwBytes
			, dwFlags
			, &toEndPoint.getAddressInfo()
			, toEndPoint.getAddressInfoSize()
			, pSendToToken
			, NULL
			);
		if (nBytesRecv == SOCKET_ERROR && (WSAGetLastError() != WSA_IO_PENDING))
		{
			pSendToToken->endInit(false);
			return false;
		}

		return true;

	}


	bool YUdpSession::recvfrom( IRecvFromCallback& callback )
	{
		DWORD dwFlags = 0;
		DWORD dwBytes = 0;

		m_recvFromToken.beginInit(callback, *this);
		int nBytesRecv = WSARecvFrom(m_socket
											, &m_recvFromToken.getWSABuf()
											, m_recvFromToken.getWSABufCount()
											, &dwBytes
											, &dwFlags
											, m_recvFromToken.getSockAddr()
											, m_recvFromToken.getSockAddrSize()
											, &m_recvFromToken
											, NULL
											);
		if (nBytesRecv == SOCKET_ERROR && (WSAGetLastError() != WSA_IO_PENDING))
		{
			m_recvFromToken.endInit(false);
			return false;
		}

		return true;
	}

	void YUdpSession::shutdown()
	{
		::shutdown(m_socket, SD_SEND);
	}

	void YUdpSession::close()
	{
		closesocket(m_socket);
		m_socket = INVALID_SOCKET;
	}

	ysimple_system::IProactor& YUdpSession::getProactor()
	{
		return m_proactor;
	}


}
